home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / UTIL / FILEUTIL / SUPPORT100 / Source / Joinf_c < prev    next >
Text File  |  1995-02-04  |  23KB  |  458 lines

  1. /********************************************************************************/
  2. /*                                                                              */
  3. /* Joinf.c                                                                      */
  4. /* Part of Splitf and Joinf distribution                                        */
  5. /* version 1.13, © 1993-1995 Adam Hamilton                                      */
  6. /* See the README file for copyright information                                */
  7. /*                                                                              */
  8. /********************************************************************************/
  9.  
  10.  
  11. /*********************************/
  12. /* Include required header files */
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include "config.h"
  19.  
  20.  
  21. /**********************************/
  22. /* Program macros and definitions */
  23.  
  24. #define TITLE "File joiner.  Version 1.13 - 4th Feburary 1995 by A.Hamilton\n\n"
  25. #ifndef Bool
  26. #  define Bool char
  27. #endif
  28. #define False   0
  29. #define True    !False
  30. #define MIN(a, b) (a < b ? a : b)
  31. #define MAX(a, b) (a > b ? a : b)
  32.  
  33.  
  34.  
  35. /********************************************************************************/
  36. /*                                                                              */
  37. /* Function    : usage                                                          */
  38. /* Description : Displays program usage to standard error, and exits.           */
  39. /* Arguments   : progname - pointer to character string containing the program  */
  40. /*                          name.                                               */
  41. /* Returns     : None.                                                          */
  42. /*                                                                              */
  43. /********************************************************************************/
  44.  
  45.  
  46. void usage (char *progname)
  47. {
  48.   fprintf (stderr, TITLE);
  49.   fprintf (stderr, "Usage : %s [options] <filename>\n\n", progname);
  50.   fprintf (stderr, "Options (can be abbreviated) :\n");
  51. #ifndef PC
  52.   fprintf (stderr, "    -buffersize   [buffersize in K]        default = 32\n");
  53. #endif
  54.   fprintf (stderr, "    -filename     [new filename]\n");
  55.   fprintf (stderr, "    -interactive\n");
  56.   fprintf (stderr, "    -info\n");
  57.  
  58.   exit (EXIT_FAILURE);
  59. }
  60.  
  61.  
  62.  
  63. /********************************************************************************/
  64. /*                                                                              */
  65. /* Function    : examine_filename                                               */
  66. /* Description : Splits filename into component parts.                          */
  67. /* Arguments   : original_name - character array, filename to be examined.      */
  68. /*               name          - pointer to a character array in which to store */
  69. /*                               file leafname (excluding extention).           */
  70. /*               path          - pointer to a character array in which to store */
  71. /*                               the destination files path.                    */
  72. /* Returns     : If the destination file has an extention, then return it,      */
  73. /*               otherwise return "".                                           */
  74. /*                                                                              */
  75. /********************************************************************************/
  76.  
  77.  
  78. char *examine_filename (char original_name[], char *name, char *path)
  79. {
  80.   char main_name[256];                  /* Temporary store for leafname.        */
  81.   char *original;                       /* Pointer to start of leafname.        */
  82.   char ext[32];
  83.   char *pointer;                        /* Pointer to any ':' characters found. */
  84.   register int i = -1, n;               /* Pointer & counter.                   */
  85.  
  86.   if (COLON)                                                    /* If our system uses ':' in    */
  87.     pointer = strrchr (original_name, ':');                     /* the file path, then remember */
  88.   else                                                          /* where it is.                 */
  89.     pointer = NULL;
  90.  
  91.   original = strrchr (original_name, SEPARATOR_SEARCH);         /* Find the address where the   */
  92.   if ((original = MAX (original, pointer)) == NULL)             /* leafname starts.             */
  93.     original = original_name;
  94.   else {
  95.     original++;
  96.     strncpy (path, original_name, original - original_name);    /* Get the path.                */
  97.     path[original - original_name] = '\0';
  98.   }
  99.  
  100.   do {
  101.     i++;
  102.     main_name[i] = original[i];                                 /* Get files leafname           */
  103.   } while (main_name[i] != '.' && main_name[i] != '\0');        /* (excluding any extention).   */
  104.  
  105.   main_name[i - 2] = '\0';                                      /* Copy the leafname.           */
  106.   strcpy (name, main_name);
  107.  
  108.   if (main_name[i] == '\0')                             /* If the file doesn't have an          */
  109.     return ("");                                        /* extention return an empty string.    */
  110.  
  111.   for (n = 0; (ext[n] = original[i]) != '\0'; n++, i++) ;       /* Otherwise get the extention  */
  112.   return (ext);                                                 /* and return it.               */
  113. }
  114.  
  115.  
  116.  
  117. /********************************************************************************/
  118. /*                                                                              */
  119. /* Function    : numtostr                                                       */
  120. /* Description : Converts a number into a 2 didget character string.            */
  121. /* Arguments   : number - number to be converted.                               */
  122. /*               name   - pointer to a character array to store the number.     */
  123. /* Returns     : None.                                                          */
  124. /*                                                                              */
  125. /********************************************************************************/
  126.  
  127.  
  128. void numtostr (short number, char *name)
  129. {
  130.   name[0] = (short) (number / 10) + '0';
  131.   name[1] = (number % 10) + '0';
  132.   name[2] = '\0';
  133. }
  134.  
  135.  
  136.  
  137. /********************************************************************************/
  138. /*                                                                              */
  139. /* Function    : main                                                           */
  140. /* Description : Main control function.                                         */
  141. /* Arguments   : Command line parameters.                                       */
  142. /* Returns     : Exit status.                                                   */
  143. /*                                                                              */
  144. /********************************************************************************/
  145.  
  146.  
  147. int main (int argc, char *argv[])
  148. {
  149.   char  source_filename[256];           /* Source filename.                     */
  150.   char  out_filename[256];              /* Output leafname.                     */
  151.   char  in_path[256];                   /* Input path.                          */
  152.   char  file_ext[32];                   /* Output extention.                    */
  153.   char  out_name[256];                  /* Full output filename.                */
  154.   char  header[50];                     /* Output file header.                  */
  155.   char  fnum[3];                        /* Output part number.                  */
  156.   char  *progname;                      /* Program name.                        */
  157.   char  string[256];                    /* Input string.                        */
  158.   char  type[5];                        /* Filetype (Acorn systems only).       */
  159.   char  interactive = 0;                /* Interactive status flag.             */
  160.   char  source_name[256];
  161.   char  check_name[256];
  162.  
  163.   short file_number = 0;                /* Current part number.                 */
  164.   short check_number;
  165.   long  read_size = 32 * 1024;          /* Buffer size (default 32K).           */
  166.   long  out_position;                   /* Position within output file.         */
  167.   long  in_position;                    /* Position within input file.          */
  168.   long  bytes_read;                     /* Number of bytes read.                */
  169.   long  bytes_written;                  /* Number of bytes written.             */
  170.   long  file_length;                    /* Length of source file.               */
  171.   long  *buffer;                        /* Pointer to buffer.                   */
  172.   int   total_number;                   /* Total number of parts to join.       */
  173.   int   args;                           /* Number of command line arguments.    */
  174.   int   i, n;                           /* Counters.                            */
  175.   Bool  info = False;                   /* Display information?                 */
  176.   FILE  *source_file;                   /* Source file ID.                      */
  177.   FILE  *out_file;                      /* Output file ID.                      */
  178.  
  179.   static char splith1[]="Split:";       /* Part 1 header check string.          */
  180.   static char splith2[]="Sp:";          /* Part >1 header check string.         */
  181.  
  182.  
  183. #ifdef ACORN
  184.   _kernel_swi_regs regs;
  185.   _kernel_oserror *err;
  186. #endif
  187.  
  188.   progname = *argv;                                     /* Get the program name.                */
  189.  
  190.   in_path[0] = '\0';                                    /* Set path to CWD.                     */
  191.   out_filename[0] = '\0';                               /* Clear destination filename.          */
  192.   source_filename[0] = '\0';                            /* Clear source filename.               */
  193.  
  194.   args = argc - 1;                                      /* Initialise count of arguments.       */
  195.   if (!args) usage (progname);                          /* If no arguments supplied, show usage.*/
  196.  
  197.   while (args--) {
  198.     argv++;                                             /* Look at next argument.               */
  199.  
  200.     if (!strncmp ("-filename", *argv, MAX (2, strlen (*argv)))) {       /* -filename            */
  201.       if (!args) {
  202.         fprintf (stderr, "Filename required\n\n");
  203.         usage (progname);
  204.       }
  205.       strcpy (out_filename, *++argv);                                   /* Read output filename.*/
  206.       args--;
  207.     }
  208.  
  209. #ifndef PC
  210.     else if (!strncmp ("-buffersize", *argv, MAX (2, strlen (*argv)))) {        /* -buffersize  */
  211.       if (!args) {
  212.     fprintf (stderr, "Buffer size required\n\n");
  213.     usage (progname);
  214.       }
  215.       read_size = (long) atoi (*++argv) * 1024;                         /* Read buffer size.    */
  216.       args--;
  217.     }
  218. #endif
  219.  
  220.     else if (!strncmp ("-interactive", *argv, MAX (2, strlen (*argv)))) /* -interactive         */
  221.       interactive = 1;
  222.  
  223.     else if (!strncmp ("-info", *argv, MAX (3, strlen (*argv))))        /* -info                */
  224.       info = True;
  225.  
  226.     else {
  227.       strcpy (source_filename, *argv);                                  /* Read source filename.*/
  228.       if (args) usage (progname);
  229.     }
  230.   }
  231.  
  232.   if (source_filename[0] == NULL) {
  233.     fprintf (stderr, "Source filename required\n\n");
  234.     usage (progname);
  235.   }
  236.  
  237.                                                         /* Get file detail from source filename.*/
  238.   strcpy (file_ext, examine_filename (source_filename, source_name, in_path));
  239.  
  240.   source_file = fopen (source_filename, "rb");          /* Open read binary source file.        */
  241.   if (source_file == NULL) {                            /* Report if error, and stop.           */
  242.     fprintf (stderr, "Fatal error opening %s for input.\n", source_filename);
  243.     exit (EXIT_FAILURE);
  244.   }
  245.  
  246.   i = 0;                                                                /* Initialise counter.  */
  247.   while ((header[i++] = fgetc (source_file)) != '|' && i < 300) ;       /* Read file header,    */
  248.   for (i = 0; i < 6; i++) if (header[i] != splith1[i]) {        /* and compare with template.   */
  249.     fprintf (stderr,"Fatal error, no split header in file %s\n", source_filename);
  250.     fclose (source_file);
  251.     exit (EXIT_FAILURE);
  252.   }
  253.  
  254.   fseek (source_file, 0L, SEEK_END);                    /* Set file pointer to end of file,     */
  255.   file_length = ftell (source_file);                    /* get file length                      */
  256.   fseek (source_file, 0L, SEEK_SET);                    /* and reset pointer to the start.      */
  257.  
  258.   n = 0;                                                                /* Initialise counter.  */
  259. #ifdef ACORN
  260.   while (header[i] != '=') {                                    /* Extract output filename,     */
  261.     out_name[n++] = (header[i] == '.' ? '/' : header[i]);       /* swapping any '.' and '/'     */
  262.     i++;                                                        /* characters.                  */
  263.   }
  264.   n++;
  265.   i++;
  266. #else
  267.   while ((out_name[n++] = header[i++]) != '=') ;                /* Just extract the filename,   */
  268. #endif
  269.  
  270.   out_name[--n] = '\0';                                         /* terminate it properly,       */
  271.   if (out_filename[0] == '\0') strcpy (out_filename, out_name); /* and copy.                    */
  272.  
  273.   n = 0;                                                        /* Initialise counter.          */
  274.   while ((fnum[n++] = header[i++]) != '=') ;                    /* Get the total number of      */
  275.   fnum[--n] = '\0';                                             /* parts.                       */
  276.   total_number = atoi (fnum);
  277.  
  278.   n = 0;                                                        /* Initialise counter.          */
  279.   while ((type[n++] = header[i++]) != '|') ;                    /* Read the filetype data.      */
  280.   type[--n] = '\0';
  281.  
  282.   if (info) {                                                   /* If -info selected, only      */
  283.     printf (TITLE);                                             /* print information.           */
  284.     printf ("Information :\n\n");
  285.     printf ("    Output filename is %s", out_filename);
  286.  
  287. #ifdef ACORN
  288.     if (type[0] == 't') {                                       /* If the file contains         */
  289.       printf (", filetype ");                                   /* filetype data then show it.  */
  290.       for (n = 1; type[n] != '\0'; n++)
  291.         printf ("%c", toupper(type[n]));
  292.     }
  293. #endif
  294.  
  295.     printf ("\n");
  296.     bytes_read = 0;
  297.   }
  298.   else {                                                /* -info not selected, do the joining.  */
  299.  
  300.     buffer = (long *) malloc ((size_t) read_size);      /* Allocate memory for a buffer.        */
  301.     if (buffer == NULL) {
  302.       fprintf (stderr, "Fatal error, unable to allocate memory block of %ld bytes\n", read_size);
  303.       exit (EXIT_FAILURE);
  304.     }
  305.  
  306.     printf ("Using buffer size of %ld bytes.\n", read_size);
  307.  
  308. #ifdef ACORN
  309.     regs.r[0] = 7;                                              /* Create the file with SWI     */
  310.     regs.r[1] = (int) out_filename;                             /* OS_File 7                    */
  311.     regs.r[2] = 0xdeaddead;
  312.     regs.r[3] = 0xdeaddead;
  313.     regs.r[4] = 0;
  314.     regs.r[5] = (int) (file_length * (total_number - 0.5));     /* using an estimated size.     */
  315.     if ((err = _kernel_swi (SWI_OS_File, ®s, ®s)) != NULL) {
  316.       fprintf (stderr, "Fatal error opening %s for output:\n-- %s\n", out_filename, err->errmess);
  317.       exit (EXIT_FAILURE);
  318.     }
  319. #endif
  320.  
  321.     out_file = fopen (out_filename, "wb");                      /* Open output file.            */
  322.     if (out_file == NULL) {                                     /* Report if error, and stop.   */
  323.       fprintf (stderr, "Fatal error opening %s for output.\n", out_filename);
  324.       exit (EXIT_FAILURE);
  325.     }
  326.   }
  327.  
  328.   out_position = 0;                             /* Initialise output file position pointer.     */
  329.  
  330.   for (file_number = 1; file_number <= total_number; file_number++) {   /* for each part        */
  331.     numtostr (file_number, fnum);
  332.     while (interactive == 1 && file_number > 1) {               /* If -interactive selected,    */
  333.       printf ("Enter path for %s%s%s (Return for %s) :\n",      /* ask for location of next     */
  334.           source_name, fnum, file_ext,                          /* part.                        */
  335.           in_path[0] == '\0' ? "current directory" : in_path);
  336.  
  337.       gets (string);                                            /* Get output destination.      */
  338.       if (strchr (string, ' ') != NULL) {
  339.         printf ("Invalid path name.\n");
  340.         continue;
  341.       }
  342.  
  343.       if (string[0] != '\0') {                  /* If nothing entered, then use the default.    */
  344.         strcpy (in_path, string);
  345.         i = strlen (in_path);
  346.         if (in_path[i - 1] != FILE_SEPARATOR)
  347.           if (!COLON || (COLON && in_path[i - 1] != ':')) {
  348.             in_path[i] = FILE_SEPARATOR;
  349.             in_path[i + 1] = '\0';
  350.           }
  351.  
  352.       }
  353.       interactive = interactive | 2;            /* Set flag to say data has been accepted.      */
  354.     }
  355.     interactive = interactive & 1;                      /* Mask off unrequired data.            */
  356.  
  357.                                                         /* Create the full input filename.      */
  358.     sprintf (source_filename, "%s%s%s%s", in_path, source_name, fnum, file_ext);
  359.  
  360.     if (file_number != 1) {                                     /* If it's not the first part,  */
  361.       source_file = fopen (source_filename, "rb");              /* Open read binary file.       */
  362.       if (source_file == NULL) {                                /* Report if error, and stop.   */
  363.         fprintf (stderr, "Fatal error opening %s for input.\n", source_filename);
  364.         exit (EXIT_FAILURE);
  365.       }
  366.  
  367.       i = 0;                                                            /* Initialise counter.  */
  368.       while ((header[i++] = fgetc (source_file)) != '|' && i<300) ;     /* Check the header     */
  369.       for (i = 0; i < 3; i++) if (header[i] != splith2[i]) {            /* with a template.     */
  370.         fprintf (stderr,"Fatal error, bad header in file %s\n", source_filename);
  371.         fclose (source_file);
  372.         exit (EXIT_FAILURE);
  373.       }
  374.  
  375.       n = 0;                                                            /* Initialise counter.  */
  376. #ifdef ACORN
  377.       while (header[i] != '=') {
  378.         check_name[n++] = (header[i]=='.' ? '/' : header[i]);           /* Swap '.' and '/'     */
  379.         i++;                                                            /* characters and check */
  380.       }                                                                 /* filename.            */
  381.       n++;
  382.       i++;
  383. #else
  384.       while ((check_name[n++] = header[i++]) != '=') ;                  /* Just check filename. */
  385. #endif
  386.  
  387.       check_name[--n] = '\0';
  388.       if (strcmp (out_name, check_name)) {                              /* Report if error      */
  389.         fprintf (stderr,"Fatal error, split file %s does not match.\n", source_filename);
  390.         fclose (source_file);
  391.         exit (EXIT_FAILURE);                                            /* and stop.            */
  392.       }
  393.  
  394.       n = 0;                                                            /* Initialise counter.  */
  395.       while ((fnum[n++] = header[i++]) != '|') ;
  396.       fnum[--n] = '\0';
  397.       check_number = atoi (fnum);                                       /* Get the part number  */
  398.       if (check_number != file_number) {                                /* and make sure it's   */
  399.         fprintf (stderr,"Fatal error, incorrect part.\n");              /* one we want.         */
  400.         fclose (source_file);
  401.         exit (EXIT_FAILURE);
  402.       }
  403.     }
  404.  
  405.     in_position = (long) i;                     /* Initialise the input file position pointer.  */
  406.  
  407.     fseek (source_file, 0L, SEEK_END);                  /* Set file pointer to end of file,     */
  408.     file_length = ftell (source_file);                  /* get file length                      */
  409.     fseek (source_file, in_position, SEEK_SET);         /* and reset pointer to start of data.  */
  410.  
  411.     if (info) {                                         /* If -info just display information.   */
  412.       printf ("    %s...%ld bytes\n", source_filename, file_length - in_position);
  413.       bytes_read += file_length - in_position;
  414.     }
  415.     else {                                              /* Otherwise, do the joining.           */
  416.       printf ("Reading data from %s.....%ld bytes\n", source_filename, file_length - in_position);
  417.       while (file_length - in_position > 0) {                                   /* If any data  */
  418.     bytes_read = fread (buffer, 1, (size_t) read_size, source_file);        /* left, read   */
  419.     bytes_written = fwrite (buffer, 1, (size_t) bytes_read, out_file);      /* and write.   */
  420.  
  421.                                         /* Check we've written the correct amount of data.      */
  422.         if (bytes_written < read_size && bytes_written < file_length-in_position) {
  423.           fprintf (stderr, "Fatal error while writing %s\n", out_filename);
  424.           exit (EXIT_FAILURE);                                  /* If unsucessfull, then stop.  */
  425.         }
  426.         in_position += bytes_read;                              /* Update the file position     */
  427.         out_position += bytes_written;                          /* pointers.                    */
  428.       }
  429.     }
  430.  
  431.     fclose (source_file);                                       /* Close the source file.       */
  432.     if (!info && (bytes_written < bytes_read)) {
  433.       fprintf (stderr, "Fatal error while writing %s\n", out_filename);
  434.       exit (EXIT_FAILURE);                                      /* If unsucessfull, stop.       */
  435.     }
  436.   }
  437.  
  438.   if (info)
  439.     printf ("\nTotal of %ld bytes contained in %d files.\n", bytes_read, total_number);
  440.  
  441.   else {
  442.     fclose (out_file);                                                  /* Close output file    */
  443.     free (buffer);                                                      /* and free buffer.     */
  444.  
  445. #ifdef ACORN
  446.     if (type[0] == 't') {                                       /* If the file had a type       */
  447.       regs.r[0] = 18;                                           /* set the filetype with SWI    */
  448.       regs.r[1] = (int) out_filename;                           /* OS_File 18                   */
  449.       sscanf (type, "t%x", ®s.r[2]);
  450.       err = _kernel_swi (SWI_OS_File, ®s, ®s);
  451.     }
  452. #endif
  453.                                                                         /* Report status        */
  454.     fprintf (stderr, "%ld bytes written to file %s\n", out_position, out_filename);
  455.   }
  456.   exit (EXIT_SUCCESS);                                                  /* and finish.          */
  457. }
  458.